# -*- coding: utf-8 -*-
#!/usr/bin/env python

"""
blog demo based on web.py & gae
by Mason
starstarstarpku@gmail.com
"""

import web
from web import template, form
from google.appengine.ext import db

from models import *
from cache import *

import math, random, cgi, logging

web.config.debug = False

urls = (
    "/", "index",
    "/add", "add",
    "/login", "login",
    "/login?redir_url=(.*)", "login",
    "/logout", "logout",
    "/edit/(\d+)", "edit",
    "/edit", "edit",
    "/view/(\d+)", "view",
    "/page/(\d+)", "page",
    "/archive", "archive",
    "/comment", "comment",
    "/tag/([^/]+)", "tag",
    "/date/(\d\d\d\d)-(\d\d)", "month_handler",
    "/manage", "manage",
    "/delete/(\d+)", "delete",
    "/clear", "clear",
    "/cc", "clear_cache",
    "/(.*)", "notfound",)
app = web.application(urls, globals())

session = web.session.Session(app, web.session.GoogleStore('colablog-session'),
    initializer={'user': 'anonymous', 'login': False, }, cache_handler=del_all)

render_globals = {'session': session}
render = template.render('templates', cache=True, base="layout", globals=render_globals)

class notfound:
  def GET(self, info):
    return template.render("templates").notfound()

app.notfound = notfound


users = {'username': 'password', }

login_form = form.Form(
    form.Textbox('username', form.Validator('Unknown username.', lambda x: x in users.keys()), description='Username:', class_="textbox"),
    form.Password('password', description="Password:", class_="textbox"),
    form.Hidden('redir_url'),
    validators = [form.Validator("Username and password didn't match.", lambda x: users[x.username] == x.password)],
    )

def get_tag_counts():
  tag_counts = Article.get_all_tags()
  result = []
  if tag_counts:
    maximum = max(tag_counts.values())

    for tag, count in tag_counts.items():
      tc = web.utils.storage(tag=tag, count=count, css_class="")
      percent = math.floor((tc.count * 100) / maximum)

      tag_cloud_size = ['tag-cloud-tiny', 'tag-cloud-small', 'tag-cloud-medium', 'tag-cloud-large', 'tag-cloud-huge', 'tag-cloud-huge']
      tc.css_class = tag_cloud_size[(int(percent))/20]

      result.append(tc)

    random.shuffle(result)
    return result

def get_month_counts():
    """
    Get date counts, sorted in reverse chronological order.

    :rtype: list
    :return: dict
    """
    hash = Article.get_all_datetimes()
    datetimes = hash.keys()
    date_count = {}
    for dt in datetimes:
      just_date = datetime.date(dt.year, dt.month, 1)
      try:
        date_count[just_date] += hash[dt]
      except KeyError:
        date_count[just_date] = hash[dt]

    dates = date_count.keys()
    dates.sort()
    dates.reverse()
    return [web.utils.storage(date=date, count=date_count[date]) for date in dates]

def get_htmlcalendar():
  import html_calendar
  today = datetime.date.today()
  return html_calendar.MonthlyCalendar(today.year, today.month).create()

class index:
  def GET(self):
    return web.seeother("page/1")

class page:
  @get_cache
  def GET(self, page):
    all_articles = db.GqlQuery("SELECT * FROM Article ORDER BY published_when DESC")
    page_count = ((all_articles.count() - 1)/10) + 1
    page = int(page)
    if page <= 0 or (page_count > 0 and page > page_count):
      raise web.seeother("notfound")

    recent_posts = all_articles.fetch(min(all_articles.count(), 20))
    articles = all_articles.fetch(10, offset = (page - 1)*10)

    # calendar show!
    #my_calendar = get_htmlcalendar()
    return render.index(articles, get_tag_counts(), recent_posts, get_month_counts(), \
                         page, page_count, ["测试"], ["solidot"])

class archive:
  @get_cache
  def GET(self):
    articles = Article.published()
    return render.archive(articles)

class tag:
  @get_cache
  def GET(self, tag):
    articles = Article.all_for_tag(tag)
    return render.tag(articles)

class month_handler:
  @get_cache
  def GET(self, year, month):
    articles = Article.all_for_month(int(year), int(month))
    return render.month(articles)

post_form = form.Form(
    form.Textbox('title', form.notnull, class_="textbox"),
    form.Textarea('body', form.notnull, cols=70, rows=20, class_="textbox"),
    form.Textbox('tag', class_="textbox"),
    form.Hidden('id'),
    )

def login_required(func):
  def handler(*args):
    if session.login is False:
      redir_url = web.ctx.fullpath
      raise web.seeother('/login?redir_url='+redir_url)
    return func(*args)
  return handler

def notlogin_required(func):
  def handler(*args):
    if session.login is True:
      raise web.seeother('/')
    return func(*args)
  return handler

def proc_tag(tags):
  if tags:
    tags = [t.strip() for t in tags.split(',')]
  else:
    tags = []
  return Article.convert_string_tags(tags)

class add:
  @login_required
  def GET(self):
    form = post_form()
    return render.add(form)

  @login_required
  def POST(self):
    form = post_form()
    if not form.validates():
      return render.add(form)

    a = Article(title=form["title"].value,
                #body=cgi.escape(form["body"].value),
                body = form["body"].value,
                tags = proc_tag(form["tag"].value))
    a.save()

    add_post_cache(a)
    return web.seeother("/")

class edit:
  @login_required
  @get_cache
  def GET(self, id):
    article = Article.get(int(id))
    if not article:
      raise web.seeother("/notfound")
    edit_form = post_form()
    edit_form["title"].value = article.title
    edit_form["body"].value = article.body
    edit_form["tag"].value = ",".join(article.tags)
    edit_form["id"].value = id
    return render.edit(edit_form, id)

  @login_required
  def POST(self):
    form = post_form()
    if not form.validates():
      id = form["id"].value
      return render.edit(form, id)

    id = form["id"].value
    a = Article.get(int(id))
    if not a:
      raise web.seeother("/notfound")

    import copy
    old_a = copy.deepcopy(a)
    a.title = form["title"].value
    a.body = form["body"].value
    a.tags = proc_tag(form["tag"].value)
    a.save()

    edit_post_cache(a, old_a)

    return web.seeother("/view/"+id)

class manage:
  @login_required
  @get_cache
  def GET(self):
    articles = db.GqlQuery("SELECT * FROM Article")
    return render.manage(articles)

class delete:
  @login_required
  def GET(self, id):
    article = Article.get(int(id))
    if article:
      del_post_cache(article)

      article.delete()
    raise web.seeother("/manage")

class clear:
  @login_required
  def GET(self):
    articles = Article.get_all()
    for article in articles:
      del_post_cache(article)

      article.delete()
    raise web.seeother("/manage")

class view:
  @get_cache
  def GET(self, id):
    article = db.GqlQuery("SELECT * FROM Article WHERE id = :1", int(id))
    comment = db.GqlQuery("SELECT * FROM Comment WHERE article_id = :1", int(id))
    prev_article = Article.get_prev(article[0].published_when)
    next_article = Article.get_next(article[0].published_when)
    if len(prev_article) == 0:
        prev_article = [None]
    if len(next_article) == 0:
        next_article = [None]
    return render.view(article, comment, prev_article[0], next_article[0])

class comment:
  def POST(self):
    i = web.input()
    c = Comment(article_id = int(i.post_id), author = i.post_username, content = i.post_body)
    c.put()

    del_paths_cache(['/', '/view/' + '%s' % i.post_id], "new comment post")

    raise web.seeother("./view/"+i.post_id)

class login:
  @notlogin_required
  def GET(self):
    login = login_form()
    index = web.ctx.fullpath.find("?redir_url=")
    redir_url = web.ctx.fullpath[index+11:]
    login['redir_url'].value = redir_url
    return render.login(session.user, login)

  @notlogin_required
  def POST(self):
    login = login_form()
    if not login.validates():
      return render.login(session.user, login)
    else:
      session.username = login['username'].value
      session.login = True

      del_all()
      raise web.seeother(login['redir_url'].value)

class logout:
  @login_required
  def GET(self):
    session.kill()

    del_all()
    raise web.seeother('/')

class clear_cache:
  def GET(self):
    del_all()
    raise web.seeother('/')

if __name__ == "__main__":
  #app.run()
  main = app.cgirun()
